/*
 *  Author bangbang.song@gmail.com
 *  
 */

package com.cngphone.AnFetion.Fetion;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;

import com.cngphone.AnFetion.tools.LogUtil;

public class FetionMessageProvider extends ContentProvider {
	private final static String TAG = "FetionHistoryProvider";
	
	private final static Boolean LOCAL_DEBUG = true;
	
	private final static UriMatcher mUriMatcher;
	private final static int MSGS = 1;
	private final static int MSGS_WHO = 2;
	
	// default DB path: /data/data/this_package_name/DATABASE_NAME
	private final static String DATABASE_NAME = "fetion.DB";
	private final static String DATABASE_TABLE = "history_message";
	private final static int DATABASE_VERSION = 1;
	
	/*
	 *  constrained by android.
	 */
	private final static String _ID = "_id";
	
	/* 
	 *  All types have been casted to String for easy-doing.
	 */
	/*
	 *  from which the message come.
	 */
	public  final static String KEY_FROM = "_from";
	public  final static int INDEX_FROM = 1;
	/*
	 * to which the message send.
	 */
	public final static String KEY_TO = "_to";
	public  final static int INDEX_TO = 2;
	/*
	 * the message itself.
	 */
	public final static String KEY_MSG = "_msg";
	public final static int INDEX_MSG = 3;
	/*
	 * at which the message is received.
	 */
	public final static String KEY_DATE = "_date";
	public final static int INDEX_DATE = 4;

	
	private SQLiteDatabase mDb;
	private FetionHistoryDBHelper mHelper;
	
	
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		if (LOCAL_DEBUG) {
		LogUtil.i(TAG, "[delete func] uri:" + uri);
		}
		
		int count = -1;
		switch (mUriMatcher.match(uri)) {
			case (MSGS): {
				count = mDb.delete(DATABASE_TABLE, selection, selectionArgs);
				LogUtil.d(TAG, "All message be deleted..");
				break;
			}
			case (MSGS_WHO): {
				String people = uri.getLastPathSegment();
				peopleIdCheck(people);
				people = escapeString(people);
				LogUtil.d(TAG, "the escaped last path segment = " + people);
				
				String where = "(( " + KEY_FROM + " = " + people + " ) " +
						       " OR ( " + KEY_TO + " = " + people + " )) " + 
				               (null == selection ? "" : " AND (" + selection + " ) ");
				if (LOCAL_DEBUG ) {
					LogUtil.d(TAG, "where = " + where);
				}
				
				count = mDb.delete(DATABASE_TABLE, 
						where, 
						selectionArgs);
				break;
			}

			default: {
				throw new IllegalArgumentException("unKnown uri: " + uri);
			}
		}
		
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		switch (mUriMatcher.match(uri)) {
			case (MSGS): {
				return Fetion.CONTENT_TYPE;
			}
			case (MSGS_WHO): {
				return Fetion.CONTENT_ITEM_TYPE;
			}
			default: {
				throw new IllegalArgumentException("unKnown uri:" + uri);
			}
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		if (LOCAL_DEBUG) {
			LogUtil.d(TAG, "[insert func] uri:" + uri);
		}
		
		switch (mUriMatcher.match(uri)) {
			case (MSGS): {
				if (null == values) {
					throw new IllegalArgumentException("the Para values cant not be null");
				}
				
				String from = values.getAsString(KEY_FROM);
				String to = values.getAsString(KEY_TO);
				peopleIdCheck(from);
				peopleIdCheck(to);
				
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
				String dateString = sdf.format(new Date());
				values.put(KEY_DATE, dateString);
				
				LogUtil.d(TAG, "the insert values is: " + values.toString());
				
				long rowId = mDb.insert(DATABASE_TABLE, null, values);
				if (rowId > 0 ) {
					Uri u = ContentUris.withAppendedId(Fetion.CONTENT_URI, rowId);
					
					getContext().getContentResolver().notifyChange(uri, null);
					return u;
				}
				
				throw new SQLException("Failed insert row into " + uri);
			}
			case (MSGS_WHO): {
				//we don't need this
				// go through
			}
			default: {
				throw new IllegalArgumentException("[inset func] unknown uri:" + uri);
			}
		}

	}

	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		mHelper = new FetionHistoryDBHelper(getContext());
		mDb = mHelper.getWritableDatabase();// overhead ??? writable VS readable
		return (mDb == null) ? false : true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		if (LOCAL_DEBUG) {
			LogUtil.d(TAG, "[query func] uri:" + uri);
		}
		
		Cursor cursor;
		switch (mUriMatcher.match(uri)) {
			case (MSGS): {
				LogUtil.v(TAG, "query all messages.");
				cursor = mDb.query(DATABASE_TABLE,projection, selection, selectionArgs, null, null, sortOrder);
				break;
			}
			case (MSGS_WHO): {
				String people = uri.getLastPathSegment();
				peopleIdCheck(people);
				LogUtil.v(TAG, "the last path segment = " + people);
				people = escapeString(people);			
				
				// how can i escape the ':' in sqlite3 ???
//				String inWhere = "((" + KEY_FROM + " = " + people + " ) " + 
//						         " OR (" + KEY_TO + " = " + people;
//				SQLiteQueryBuilder  query = new SQLiteQueryBuilder();
//				query.setTables(DATABASE_TABLE);
//				query.appendWhereEscapeString(inWhere);
//				cursor = query.query(mDb, projection, selection, selectionArgs, null, null, sortOrder);
				
				// maybe the SQLQueryHelper 
				
				String where =  " ((" + KEY_FROM + " = " + people + ") " + 
						        " OR (" + KEY_TO + " = " + people + ")) " +
						        (null == selection ? "" : " AND ("+ selection + ")");
				LogUtil.v(TAG, "where = [" + where + "]");
				
				cursor = mDb.query(DATABASE_TABLE, projection, 
						where, 
						selectionArgs, null, null, sortOrder);
				break;
			}
			default: {
				throw new IllegalArgumentException("unknown uri:" + uri);
			}
		}
				
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		return cursor;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		
		// do not need this
		return 0;
	}
	private String escapeString(String peopleId){
//		return peopleId.replaceAll(":", "\\\\:");
		return "'" + peopleId + "'";
	}
	private void peopleIdCheck(String id){
		if (!Pattern.matches("sip:[0-9]*", id) &&
			!Pattern.matches("tel:[0-9]*", id)) {
			LogUtil.v(TAG, "the people id = " + id);
				throw new IllegalArgumentException("u people id must be sip:### or tel:###, plz check");
			}
	}
	/*
	 * Helper class for creating and updating the DB.
	 */
	private static class FetionHistoryDBHelper extends SQLiteOpenHelper {
		
		private final static String CREATE_TABLE = 
								"CREATE TABLE " + 	
								" IF NOT EXISTS " + 
								DATABASE_TABLE + " ( " + // fuck the leading and trimming space 
								_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + 
								KEY_FROM + " TEXT NOT NULL, " +
								KEY_TO + " TEXT NOT NULL, " + 
								KEY_MSG + " TEXT NOT NULL, " +
								KEY_DATE + " TEXT NOT NULL " +
								");";
		public FetionHistoryDBHelper(Context context) {
			// TODO Auto-generated constructor stub
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}
		@Override
		public void onCreate(SQLiteDatabase db) {
			// TODO Auto-generated method stub
			db.execSQL(CREATE_TABLE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			// TODO Auto-generated method stub
			// TODO How can i upgrade a DB?
		}
	}
	
	/*
	 * 
	 *  convenience define for provider.
	 */
	public static final class Fetion {
		private Fetion(){}
		
		/*
		 *   get all messages: CONTENT_URI/msgs
		 *   
		 *   get some one's message CONTENT_URI/msgs/people/who_u_want_see 
		 */
		public final static String AUTHORITY = "com.bangbang.provider.FetionMessage";
		public final static Uri CONTENT_URI = 
									Uri.parse("content://" + AUTHORITY + "/msgs");
		public final static String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.bangbang.msg";
		public final static String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.bangbang.msg";
	}
	
	static {
		mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		
		mUriMatcher.addURI(Fetion.AUTHORITY, "msgs", MSGS);
		mUriMatcher.addURI(Fetion.AUTHORITY, "msgs/people/*", MSGS_WHO);
	}
	
}
